/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package weka.attributeSelection.semiAS;

import weka.core.Instance;
import weka.core.Instances;

/**
 *
 * @author Administrator
 */
public class DataSpliter {

    private Instances m_trainInstances;
    private int m_numClasses;
    private int m_nLabled;
    private int m_numInstances;
    private int m_classIndex;
    private boolean m_isNumeric;
    private boolean[] m_IsLabeled;
    private Instances m_labeledInstances;
    private Instances[] m_data;

    public DataSpliter(Instances data, Instances labledData, Instances[] classData, int nLabled, boolean[] bLabled) {
        m_trainInstances = data;
        m_labeledInstances = labledData;
        m_data = classData;
        m_numClasses = m_trainInstances.numClasses();
        m_numInstances = m_trainInstances.numInstances();
        m_classIndex = m_trainInstances.classIndex();
        m_isNumeric = m_trainInstances.attribute(m_classIndex).isNumeric();
        m_nLabled = nLabled;
        m_IsLabeled = bLabled;
    }

    public void split() throws Exception {
        int[] classTotalNums = new int[m_numClasses];
        int[] classSplitNums = new int[m_numClasses];
        int[] classCurNums = new int[m_numClasses];
        int nValid = 0;

        for (int i = 0; i < m_numInstances; i++) {
            if (m_trainInstances.instance(i).classIsMissing() == false) {
                m_IsLabeled[i] = true;
                nValid++;
            } else {
                m_IsLabeled[i] = false;
            }
        }

        if (m_nLabled == -1) {//标记样本数-1表示全标记
            m_nLabled = nValid;
        } else if (m_nLabled > nValid) {//标记样本数超过最大值取最大值
            m_nLabled = nValid;
        } else if (m_nLabled < 0) {//标记样本数小于0取0
            m_nLabled = 0;
        }
        if (m_nLabled < m_numClasses && m_nLabled > 0) {//标记样本数小于类别个数取类别个数，保证每一类均有标记
            m_nLabled = m_numClasses;
        }
        if (m_nLabled > 0 && m_nLabled < nValid) {//非全标记和全不标记
            for (int i = 0; i < m_numInstances; i++) {  //classTotalNums
                if (!m_IsLabeled[i]) {//缺失类别信息的数据
                    continue;
                }
                int classIndex;
                if (!m_isNumeric) {
                    classIndex = (int) m_trainInstances.instance(i).value(m_classIndex);
                } else {
                    classIndex = 0;
                }
                classTotalNums[classIndex]++;
            }
//            for (int i = 0; i < m_numInstances; i++) {  //classSplitNums
//                int classIndex;
//                if (!m_isNumeric) {
//                    classIndex = (int) m_trainInstances.instance(i).value(m_classIndex);
//                } else {
//                    classIndex = 0;
//                }
//                classSplitNums[classIndex] = (int) (classTotalNums[classIndex] * m_nLabled);
//            }
            int nUnlabled = nValid - m_nLabled;
            double unPercent = nUnlabled * 1.0 / nValid;
            int sum = 0;
            for (int i = 0; i < m_numClasses; i++) {
                classSplitNums[i] = (int) (classTotalNums[i] * unPercent);
                if (classSplitNums[i] == classTotalNums[i]) {//每类至少保留一个标记样本
                    classSplitNums[i] = classTotalNums[i] - 1;
                }
                sum += classSplitNums[i];
            }
            //百分数的整数误差(小于类别个数)依次归于各类，直至分完
            for (int i = 0; sum < nUnlabled && i < m_numClasses; i++) {
                classSplitNums[i]++;
                sum++;
            }
            for (int i = 0; i < m_numInstances; i++) {  //将含有类别信息的数据分层抽样标记为无监督数据
                if (!m_IsLabeled[i]) {//缺失类别信息的数据
                    continue;
                }
                int classIndex;
                if (!m_isNumeric) {
                    classIndex = (int) m_trainInstances.instance(i).value(m_classIndex);
                } else {
                    classIndex = 0;
                }
                if (m_IsLabeled[i] == true && classCurNums[classIndex] < classSplitNums[classIndex]) {
                    m_IsLabeled[i] = false;
                    classCurNums[classIndex]++;
                }
            }
        }

        if (m_nLabled == 0) {
            for (int i = 0; i < m_numInstances; i++) {
                m_IsLabeled[i] = false;
            }
        }
        
        if (m_nLabled != 0) {
            for (int i = 0; i < m_numInstances; i++) {
                if (m_IsLabeled[i]) {
                    m_labeledInstances.add(m_trainInstances.instance(i));
                }
            }
            for (int k = 0; k < m_nLabled; k++) {
                Instance inst = m_labeledInstances.instance(k);
                int c = (int) inst.value(m_classIndex);
                m_data[c].add(inst);
            }
        }

    }
}
